package ru.niir.goodfil.audit.service;

import org.apache.log4j.Logger;
import org.hibernate.SessionFactory;
import org.hibernate.StatelessSession;
import org.hibernate.Transaction;
import ru.niir.goodfil.audit.client.AuditService;
import ru.niir.goodfil.audit.domain.*;
import ru.niir.goodfil.audit.domain.enums.Crud;
import ru.niir.goodfil.audit.domain.enums.EnviromentSubsystem;
import ru.niir.goodfil.audit.domain.enums.IntegrityEvent;
import ru.niir.goodfil.audit.domain.enums.LoginAction;

import java.io.File;
import java.io.FileReader;
import java.util.Date;
import java.util.Properties;

public class AuditServiceImpl implements AuditService {
    private static final Logger logger = Logger.getLogger(AuditServiceImpl.class);

    private static final String AUDIT_PROPS = System.getProperty("user.home") + File.separator + "audit.props";

    private final Configuration configuration;

    private SessionFactory sessionFactory;

    private boolean skipLogEvent = false;

    public AuditServiceImpl(Configuration configuration) {
        try {
            Properties props = new Properties();
            props.load(new FileReader(AUDIT_PROPS));
            if ("true".equals(props.getProperty("disable"))) {
                skipLogEvent = true;
            }
        } catch (Exception e) {
            logger.warn("audit.props not found!");
        }

        this.configuration = configuration;
    }

    private void logEvent(Event event) {
        if (skipLogEvent) {
            logger.debug("Log skipped!");
            return;
        }

        try {
            SessionFactory sessionFactory = getSessionFactory();
            StatelessSession session = sessionFactory.openStatelessSession();
            Transaction tx = session.beginTransaction();

            try {
                session.insert(event);
                tx.commit();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (!tx.wasCommitted()) {
                    tx.rollback();
                }

                session.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private SessionFactory getSessionFactory() {
        if (sessionFactory == null) {
            sessionFactory = configuration.getSessionFactory();
        }
        return sessionFactory;
    }

    public void logLoginAttempt(String ip, String login) {
        logEvent(new LoginEvent(ip, login, LoginAction.LOGIN_ATTEMPT));
    }

    public void logLoginSuccess(String ip, String login) {
        logEvent(new LoginEvent(ip, login, LoginAction.LOGIN_SUCCESS));
    }

    public void logEnviromentSubsystemLost(EnviromentSubsystem subsystem) {
        logEvent(new EnviromentIntegrityEvent(subsystem, IntegrityEvent.LOST));
    }

    public void logEnviromentSubsystemFound(EnviromentSubsystem subsystem) {
        logEvent(new EnviromentIntegrityEvent(subsystem, IntegrityEvent.FOUND));
    }

    public void logExceptionEvent(String ip, String login, String exception, String stacktrace) {
        logEvent(new ExceptionEvent(ip, login, exception, stacktrace));
    }

    public void logEntityCreate(String ip, String login, String klass, String orderXml) {
        logEvent(new EntityEvent(ip, login, Crud.CREATE, klass, orderXml));
    }

    public void logEntityUpdate(String ip, String login, String klass, String orderChangeXml) {
        logEvent(new EntityEvent(ip, login, Crud.UPDARE, klass, orderChangeXml));
    }

    public void logEntityDelete(String ip, String login, String klass, String orderXml) {
        logEvent(new EntityEvent(ip, login, Crud.DELETE, klass, orderXml));
    }

    public void logSettingModification(String ip, String login, String optionKey, String newOptionValue, String oldOptionValue) {
        logEvent(new SettingModificationEvent(ip, login, optionKey, newOptionValue, oldOptionValue));
    }

    public void logPasswordChange(String ip, String login, String userLogin, String address) {
        logEvent(new PasswordChangeEvent(ip, login, userLogin, address));
    }

    public void logPersonalPriceCreation(String ip, String login, Long goodId, String goodCode, String goodName, Long clientId, String clientName, Float price, Date begdate, Date enddate) {
        PersonalPriceEvent event = new PersonalPriceEvent();
        event.setIp(ip);
        event.setLogin(login);
        event.setCrud(Crud.CREATE);
        event.setGoodId(goodId);
        event.setGoodCode(goodCode);
        event.setGoodName(goodName);
        event.setClientId(clientId);
        event.setClientName(clientName);
        event.setPrice(price);
        event.setBegdate(begdate);
        event.setEnddate(enddate);
        logEvent(event);
    }

    public void logPersonalPriceDeletion(String ip, String login, Long goodId, String goodCode, String goodName, Long clientId, String clientName, Float price, Date begdate, Date enddate) {
        PersonalPriceEvent event = new PersonalPriceEvent();
        event.setIp(ip);
        event.setLogin(login);
        event.setCrud(Crud.DELETE);
        event.setGoodId(goodId);
        event.setGoodCode(goodCode);
        event.setGoodName(goodName);
        event.setClientId(clientId);
        event.setClientName(clientName);
        event.setPrice(price);
        event.setBegdate(begdate);
        event.setEnddate(enddate);
        logEvent(event);
    }

    @Override
    public void logUserUIEvent(UserUIEvent userUIEvent) {
        logEvent(userUIEvent);
    }

    @Override
    public void logClientUIEvent(ClientUIEvent clientUIEvent) {
        logEvent(clientUIEvent);
    }

    @Override
    public void logClientC1NumChange(ClientC1NumChangeEvent event) {
        logEvent(event);
    }

    @Override
    public void logClientDebtChanged(ClientDebtChangeEvent event) {
        logEvent(event);
    }

    @Override
    public void logClientPriceColumnChange(ClientPriceColumnChangeEvent event) {
        logEvent(event);
    }

    @Override
    public void logClientDeliveryInfoChange(ClientDeliveryInfoChangeEvent event) {
        logEvent(event);
    }

    @Override
    public void logOrderUIBuild(OrderUIBuildEvent event) {
        logEvent(event);
    }

    @Override
    public void logReplacementUIEvent(ReplacementUIEvent event) {
        logEvent(event);
    }

    @Override
    public void logGoodUIEvent(GoodUIEvent event) {
        logEvent(event);
    }

    @Override
    public void logOrderUIEvent(OrderUIEvent event) {
//        logEvent(event);
    }

    @Override
    public void logOrderItemUIEvent(OrderItemUIEvent event) {
        logEvent(event);
    }
}
